package com.dream.rpc.spi;

import ch.qos.logback.core.recovery.ResilientOutputStreamBase;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import com.dream.rpc.serializer.Serializer;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Array;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Dreamer
 */
@Slf4j
public class SpiLoader {

    /**
     * 存储已经加载的类：接口名=>(key=>实现类)
     */
    private static Map<String, Map<String, Class<?>>> loaderMap = new ConcurrentHashMap<>();

    /**
     * 对象缓存实例，避免重复创建
     */
    private static Map<String, Object> instanceCache = new ConcurrentHashMap<>();

    /**
     * 系统SPI目录
     */
    public static final String RPC_SYSTEM_SPI_DIR = "META-INF/rpc/system";

    /**
     * 用户自定义SPI目录
     */
    public static final String RPC_USER_SPI_DIR = "META-INF/rpc/custom";

    /**
     * 扫描路径
     */
    public static final String[] SCAN_DIRS = new String[]{RPC_SYSTEM_SPI_DIR, RPC_USER_SPI_DIR};

    /**
     * 动态加载的类列表
     */
    public static final List<Class<?>> LOAD_CLASS_LIST = Arrays.asList(Serializer.class);


    /**
     * 记载所有的spi
     */
    public static void loadAll() {
        log.info("加载所有的spi");
        for (Class<?> aClass : LOAD_CLASS_LIST) {
            load(aClass);
        }
    }




    /**
     * 加在某个类型的所有实现类
     * @param loadClass
     * @return
     */
    public static Map<String, Class<?>> load(Class<?> loadClass) {
        //扫描路径，用户自定义的SPI优先级高与系统SPI
        Map<String, Class<?>>  keyClassMap = new HashMap<>();

        for (String scanDir : SCAN_DIRS) {
            List<URL> resources = ResourceUtil.getResources(scanDir + loadClass.getName());
            for (URL resource : resources) {
                try {
                    InputStreamReader inputStreamReader = new InputStreamReader(resource.openStream());
                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                    String line;
                    while ((line = bufferedReader.readLine()) != null) {
                        String[] strArray = line.split("=");
                        if (strArray.length > 1) {
                            String key = strArray[0];
                            String className = strArray[1];
                            keyClassMap.put(key, Class.forName(className));
                        }
                    }
                } catch (Exception e) {
                    log.error("spi resource load error", e);
                }

            }
        }
        loaderMap.put(loadClass.getName(), keyClassMap);
        return keyClassMap;
    }

    public static <T> T getInstance(Class<?> clazz, String key) {
        String name = clazz.getName();

        Map<String, Class<?>> classMap = loaderMap.get(name);

        if (CollectionUtil.isEmpty(classMap)) {
            throw new RuntimeException(String.format("spiloadeer未加载 %s 类型", name));
        }
        if (!classMap.containsKey(key)) {
            throw new RuntimeException(String.format("spiloadeer未加载 %s 类型的key %s", name,key));
        }

        Class<?> aClass = classMap.get(key);
        String instanceClassName = aClass.getName();
        if (!instanceCache.containsKey(instanceClassName)) {

            try {
                instanceCache.put(instanceClassName, aClass.newInstance());
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(String.format("%s 类实例化失败", instanceClassName), e);
            }
        }
        return (T)instanceCache.get(instanceClassName);

    }







}
